package com.tqz.rc.server.core;

import com.tqz.rc.api.BeatInfo;
import com.tqz.rc.api.Cluster;
import com.tqz.rc.api.Instance;
import com.tqz.rc.common.constant.DefaultValueConstant;
import com.tqz.rc.common.exception.RcException;
import com.tqz.rc.common.util.ApplicationContextUtil;
import com.tqz.rc.common.util.StringUtils;
import com.tqz.rc.server.consistency.KeyBuilder;
import com.tqz.rc.server.consistency.RecordListener;
import com.tqz.rc.server.healthcheck.ClientBeatCheckTask;
import com.tqz.rc.server.healthcheck.ClientBeatProcessor;
import com.tqz.rc.server.healthcheck.HealthCheckReactor;
import com.tqz.rc.server.push.UdpPushService;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * <p>服务的对象，一个服务包含多个集群，每个集群又包含多个实例。
 *
 * @author tianqingzhao
 * @since 2021/8/26 14:05
 */
public class Service implements RecordListener<Instances> {

    /**
     * 命名空间的id。
     */
    private String namespaceId = DefaultValueConstant.DEFAULT_NAMESPACE_ID;

    /**
     * 该服务的名称。
     */
    private String serviceName;

    /**
     * 分组名。
     */
    private String groupName;

    /**
     * 该服务下面的集群集合。key为集群名称，value为集群
     */
    private Map<String, Cluster> clusterMap = new ConcurrentHashMap<>();

    private ClientBeatCheckTask clientBeatCheckTask = new ClientBeatCheckTask(this);

    public String getNamespaceId() {
        return namespaceId;
    }

    public void setNamespaceId(String namespaceId) {
        this.namespaceId = namespaceId;
    }

    public String getServiceName() {
        return serviceName;
    }

    public void setServiceName(String serviceName) {
        this.serviceName = serviceName;
    }

    public String getGroupName() {
        return groupName;
    }

    public void setGroupName(String groupName) {
        this.groupName = groupName;
    }

    public Map<String, Cluster> getClusterMap() {
        return clusterMap;
    }

    public void setClusterMap(Map<String, Cluster> clusterMap) {
        this.clusterMap = clusterMap;
    }

    /**
     * 进行健康检查的定时任务
     */
    public void init() {
        HealthCheckReactor.scheduleCheck(clientBeatCheckTask);
    }

    @Override
    public void onChange(String key, Instances value) throws RcException {
        for (Instance instance : value.getInstanceList()) {
            if (instance == null) {
                throw new RcException("instance is null");
            }

            // TODO 设置权重，此demo可忽略，后续慢慢补充
        }

        updateIps(value.getInstanceList(), KeyBuilder.matchEphemeralInstanceListKey(key));
    }

    private void updateIps(Collection<Instance> instances, boolean ephemeral) {
        Map<String, List<Instance>> ipMap = new HashMap<>(clusterMap.size());

        for (String key : clusterMap.keySet()) {
            ipMap.put(key, new ArrayList<>());
        }

        for (Instance instance : instances) {
            if (instance == null) {
                System.out.println("instance is null。");
                continue;
            }

            // 集群名称为空，给一个默认的
            if (StringUtils.isBlank(instance.getClusterName())) {
                instance.setClusterName(DefaultValueConstant.DEFAULT_CLUSTER_NAME);
            }

            // 如果该服务没有这个集群的名称就创建一个默认的
            /*if (!clusterMap.containsKey(instance.getClusterName())) {
                System.out.println("cluster: " + instance.getClusterName()+ " 没有找到，将会创建一个默认的集群，并丢到clusterMap中。");
                Cluster cluster = new Cluster(instance.getClusterName(), this);
                cluster.init();

            }*/
            ipMap.put(instance.getClusterName(), (List<Instance>) instances);
        }

        for (Map.Entry<String, List<Instance>> entry : ipMap.entrySet()) {
            List<Instance> entryIps = entry.getValue();
            clusterMap.get(entry.getKey()).updateIps(entryIps, ephemeral);
        }

        // 通知订阅该服务的客户端
        getUdpPushService().serviceChanged(this);
    }

    /**
     * 获取集群下所有的实例。
     *
     * @param ephemeral 是否是临时节点，<code>true</code>为是，<code>false</code>为不是
     * @return
     */
    public List<Instance> allIps(boolean ephemeral) {
        List<Instance> result = new ArrayList<>();
        for (Map.Entry<String, Cluster> entry : clusterMap.entrySet()) {
            result.addAll(entry.getValue().allIps(ephemeral));
        }

        return result;
    }

    /**
     * 处理客户端心跳
     *
     * @param beatInfo 心跳对象，{@link BeatInfo}
     */
    public void processClientBeat(BeatInfo beatInfo) {
        ClientBeatProcessor clientBeatProcessor = new ClientBeatProcessor();
        clientBeatProcessor.setBeatInfo(beatInfo);
        clientBeatProcessor.setService(this);
        HealthCheckReactor.scheduleNow(clientBeatProcessor);
    }

    public UdpPushService getUdpPushService() {
        return ApplicationContextUtil.getBean(UdpPushService.class);
    }
}
